<?php

namespace app\common\model;

use think\Model;
use think\Loader;
use extend\Tree;

class BackendRuleModel extends Model
{
    protected $pk = 'id';
    protected $table = 'basic_backend_rule';
    protected $_all_user_rule = [];
    protected $_all_forbidden_rule = null;
    protected $_AllNeedMenu;

    //获取全局禁用的规则
    public function getForbiddenList($params){
        $curPage = isset($params['page'])&&$params['page']>=1  ? $params['page']: 1;
        $pageSize = 25;
        $where = [
            'a.status' => ['neq', 111],
            'a.user_group_id' => 0,
        ];

        $totalRow = self::alias("a")->where($where)->count();
        $data = self::where($where)
        ->alias("a")
        ->field("a.*,m.url")
        ->page($curPage, $pageSize)
        ->join("basic_backend_menu m","a.menu_id = m.id")
        ->select();
        $data = empty($data) ? [] : collection($data)->toArray();

        return [
            'pageSize' => $pageSize,
            'totalRow' => $totalRow,
            'curPage' => $curPage,
            'data' => $data
        ];
    }

    //获取用户所有权限
    public function setAllUserRule($userGroupId)
    {
        $this->_all_user_rule = (new BackendMenuModel())->getAllUserGorupMenuData($userGroupId);
    }

    //增加权限
    public function addRule($data, $userGroupId)
    {
        //获取用户权限
        $allMenu = (new BackendMenuModel)->getAllMenu();
        $ispost = array_column($allMenu, "is_post", "id");
        $isAccept = array_column($allMenu, "is_accept", "id");
        //插入权限与权限关联表
        $rule = [];
        foreach ($data['menu_id'] as $key => $menu_id) {
            $param = isset($data['param'][$menu_id]) ? $data['param'][$menu_id] : '';
            $is_post = $ispost[$menu_id]==1&&isset($data['is_post'][$menu_id]) ? $data['is_post'][$menu_id] : 0;
            $is_accept = $isAccept[$menu_id]==1&&isset($data['is_accept'][$menu_id]) ? $data['is_accept'][$menu_id] : 0;
            $rule[] = [
                'user_group_id' => $userGroupId,
                'menu_id' => $menu_id,
                'is_accept' => $is_accept,
                'param' => $param,
                'is_post' => $is_post
            ];
        }

        return self::saveAll($rule);
    }


    //编辑
    public function editRule($data, $userGroupId)
    {
        //获取原先权限组的权限
        $oldRuleGroupData = $this->getRuleByGroupId($userGroupId);
        $oldRuleGroupIds = [];
        foreach ($oldRuleGroupData as $key => $vo) {
            $oldRuleGroup[$vo['menu_id']] = $vo;
            $oldRuleGroupIds[] = $vo['menu_id'];
        }

        //新增的id
        $addRuleGroupIds = array_diff($data['menu_id'], $oldRuleGroupIds);
        $delRuleGroupIds = array_diff($oldRuleGroupIds, $data['menu_id']);
        $editRuleGroupIds = array_intersect($data['menu_id'], $oldRuleGroupIds);

        $user_group = [];
        foreach ($data['menu_id'] as $key => $menuId) {
            $param = isset($data['param'][$menuId]) ? $data['param'][$menuId] : '';
            $ispost = isset($data['is_post'][$menuId]) ? $data['is_post'][$menuId] : 0;
            $isAccept = isset($data['is_accept'][$menuId]) ? $data['is_accept'][$menuId] : 0;

            $temp = [
                'user_group_id' => $userGroupId,
                'menu_id' => $menuId,
                'is_accept' => $isAccept,
                'param' => $param,
                'is_post' => $ispost
            ];
            if (in_array($menuId, $editRuleGroupIds)) {
                $temp['id'] = $oldRuleGroup[$menuId]['id'];
            }
            $user_group[] = $temp;
        }

        if (!empty($delRuleGroupIds)) {
            self::destroy(['user_group_id' => $userGroupId, 'menu_id' => ['in', $delRuleGroupIds]]);
        }

        return self::saveAll($user_group);
    }


    //获取权限组的权限
    public function getMneuRuleByGroupId($id)
    {
        //获取所有的菜单
        $menuData = (new BackendMenuModel())->getAllMenu();
        //获取权限组下面的权限
        $ruleData = $this->getRuleByGroupId($id);
        $rule = [];
        foreach ($ruleData as $vo) {
            $rule[$vo['menu_id']] = $vo;
        }
        //组装数据
        foreach ($menuData as $key => $menu) {
            $temp = isset($rule[$menu['id']]) ? $rule[$menu['id']] : [];
            $menuData[$key]['selected'] = 0;
            $menuData[$key]['is_origin_post'] = $menu['is_post'];
            $menuData[$key]['is_origin_accept'] = $menu['is_accept'];
            $menuData[$key]['is_post'] = 1;
            $menuData[$key]['is_accept'] = 1;
            $menuData[$key]['param'] = "";
            if (!empty($temp)) {
                $menuData[$key]['selected'] = 1;
                $menuData[$key]['is_post'] = $temp['is_post'];
                $menuData[$key]['is_accept'] = $temp['is_accept'];
                $menuData[$key]['param'] = $temp['param'];
            }
        }

        Loader::import('Tree', EXTEND_PATH);
        $Tree = new Tree();
        $Tree->init($menuData, 'menu_name');
        $treelist = $Tree->get_tree_list();

        return $treelist;
    }


    //获取单个权限组菜单
    public function getRuleByGroupId($id)
    {
        $where = [
            'status' => ['neq', 111],
            'user_group_id' => $id,
        ];

        $rule = self::where($where)->select();
        $rule = empty($rule) ? [] : collection($rule)->toArray();

        return $rule;
    }

    public function getRuleById($id)
    {
        return self::find($id);
    }


    //检查是否拥有权限
    public function isAccept()
    {
        //获取请求路径
        $requestUrl = getRequestUrl();
        //获取拥有的全权限
        $rule = $this->getUserRule();
        //开始验证
        $isAccept = false;
        $isParamAccept = true;
        $url = $requestUrl['url'];
        $wild = $requestUrl['wild'];
        $param = [];
        $isPost = false;
        $ruleAccept = false;
        $checkUrl = '';

        //后台首页跳过验证
        if ($url == "/admin/index/index") {
            return true;
        }

        if (isset($rule[$url])) {
            //验证具体控制器方法
            $ruleAccept = boolval($rule[$url]['is_accept']);
            $param = isset($rule[$url]['param']) ? $rule[$url]['param'] : [];
            $isPost = boolval($rule[$url]['is_post'] == 1);
            $checkUrl = $url;
        } elseif (isset($rule[$wild])) {
            //验证控制器不验证方法
            $ruleAccept = boolval($rule[$wild]['is_accept']);
            $param = isset($rule[$wild]['param']) ? $rule[$wild]['param'] : [];
            $isPost = boolval($rule[$wild]['is_post'] == 1);
            $checkUrl = $wild;
        } else {
            return false;
        }

        //验证参数
        if (!empty($param)) {
            foreach ($param as $paramKey => $paramValue) {
                //存在参数则验证，不存在则不验证
                if (!isset($requestUrl['param'][$paramKey]) || $this->isParamCheck($requestUrl['param'][$paramKey], $paramValue) === false) {
                    $isParamAccept = false;
                    break;
                }
            }
        }
        $isAccept = $isParamAccept === true ? true : false;

        //验证post
        if ($isAccept && $requestUrl['is_post']) {
            $isPost == true ? $isAccept = true : $isAccept = false;
        }

        if (($isAccept && $ruleAccept) || (!$isAccept && !$ruleAccept)) {
            //检查全局禁用规则
            if($this->forbiddenRule($checkUrl, $requestUrl['is_post'], $requestUrl['param'])){
                return false;
            }

            return true;
        } else {
            return false;
        }
        return false;
    }

    //获取加工过的用户权限
    public function getUserRule()
    {
        $ruleData = $this->_all_user_rule;

        if (empty($ruleData)) {
            return [];
        }
        $rule = [];
        foreach ($ruleData as $key => $vo) {
            //额外参数
            $param = $vo['param'] != '' ? explode("&", $vo['param']) : [];
            $params = [];
            foreach ($param as $key => $paramVo) {
                $temp = [];
                preg_match('/(\w+)([=><])([^&]+)/', $paramVo, $temp);
                if (!empty($temp) && count($temp) == 4) {
                    if (strpos($temp[3], "||") !== false) {
                        $temp[3] = explode("||", $temp[3]);
                    }
                    $params[$temp[1]] = [$temp[2], $temp[3]];
                }
            }
            //后台地址
            $url = strtolower($vo['url']);
            $rule[$url] = [
                'parent_id' => $vo['parent_id'],
                'menu_name' => $vo['menu_name'],
                'url' => $url,
                'is_post' => $vo['is_post'],
                'is_accept' => $vo['is_accept'],
                'param' => $params,
            ];
        }
        return $rule;
    }


    //验证权限参数
    public function isParamCheck($checkValue, $paramValue)
    {
        switch ($paramValue[0]) {
            case '=':
                $paramValue[1] = is_string($paramValue[1]) ? [$paramValue[1]] : $paramValue[1];
                if (!in_array($checkValue, $paramValue[1])) {
                    return false;
                }
                break;
            case '>':
                return $checkValue > $paramValue[1] ? true : false;
                break;
            case '<':
                return $checkValue < $paramValue[1] ? true : false;
                break;
            case '>=':
                return $checkValue >= $paramValue[1] ? true : false;
                break;
            case '<=':
                return $checkValue <= $paramValue[1] ? true : false;
                break;
            default:
                return false;
                break;
        }
        return true;
    }

    //检查后台全局禁用规则
    public function forbiddenRule($checkUrl, $isPost, $params){
        $ForbiddenRule = $this->getAllForbiddenRule();

        if(!isset($ForbiddenRule[$checkUrl])){
            return false;
        }
        $tempUrl = $ForbiddenRule[$checkUrl];
        $isForbidden = false; 
        foreach($tempUrl as $temp){
            //符合请求方式
            if($temp['is_post']==0 ||($temp['is_post']==1&&$isPost==true)){
                $flag = true;
                foreach($temp['param'] as $key => $value){
                    if(isset($params[$key])){
                        $checkRule = $this->isParamCheck($params[$key], $value);
                        if($checkRule === false&&$flag == true){
                            // dump( $value );die();
                            $flag = false;
                        }
                    }else{
                        return true;
                    }
                }
                if($isForbidden == false){
                    $isForbidden = $flag;
                }

            }
        }
        

        return $isForbidden;
    }

    //获取后台全局禁用规则
    public function getAllForbiddenRule(){
        if($this->_all_forbidden_rule!==null){
            return $this->_all_forbidden_rule;
        }
        //获取所有的菜单
        $menuData = $this->getAllNeedMenu();

        //获取权限组下面的权限
        $ruleData = $this->getRuleByGroupId(0);
        
        $ForbiddenRule = [];
        foreach($ruleData as $rule){
            $url = $menuData[$rule['menu_id']]['url'];
            //额外参数
            $param = $rule['param'] != '' ? explode("&", $rule['param']) : [];
            $params = [];
            foreach ($param as $key => $paramVo) {
                $temp = [];
                preg_match('/(\w+)(=|>=|<=|<)([^&]+)/', $paramVo, $temp);
                if (!empty($temp) && count($temp) == 4) {
                    if (strpos($temp[3], "||") !== false) {
                        $temp[3] = explode("||", $temp[3]);
                    }
                    $params[$temp[1]] = [$temp[2], $temp[3]];
                }
            }

            $ForbiddenRule[$url][] = [
                'param' => $params,
                'is_post' => $rule['is_post']
            ]; 
        }

        $this->_all_forbidden_rule = $ForbiddenRule;
        return $ForbiddenRule;
    }

    //获取处理过的菜单
    public function getAllNeedMenu(){
        if($this->_AllNeedMenu !== null){
            return $this->_AllNeedMenu;
        }
        $menuData = (new BackendMenuModel())->getAllMenuData();
        $menuList = [];
        foreach($menuData as $menu){
            $menuList[$menu['id']] = $menu;
        }
        $this->_AllNeedMenu = $menuList;
        return $menuList;
    }

    //删除
    public function deleteall($id)
    {
        if (!is_array($id)) {
            $id = [$id];
        }

        return self::where("id", "in", $id)->update([
            'status' => 111,
            'update_time' => time()
        ]);
    }
}
